﻿using System.Reflection;
using ApiLib.AppStart;
using ApiLib.Models;
using ApiLib.Utils;
using CSRedis;
using Furion;
using Microsoft.Extensions.Caching.Memory;
using SqlSugar;

namespace ApiLib.Helpers;

/// <summary>
/// 数据库工具类
/// </summary>
public static class DbHelper
{
    private const string SystemModule = "System";

    /// <summary>
    /// 数据库
    /// </summary>
    public static ISqlSugarClient Db => App.GetService<ISqlSugarClient>();

    /// <summary>
    /// 新连接
    /// </summary>
    public static ISqlSugarClient DbNew => Db.CopyNew();

    /// <summary>
    /// 缓存
    /// </summary>
    public static IMemoryCache Cache => App.GetService<IMemoryCache>();

    /// <summary>
    /// 数据库
    /// </summary>
    public static SqlSugarScope? DbScope => Db as SqlSugarScope;

    /// <summary>
    /// Redis
    /// </summary>
    public static CSRedisClient Redis => RedisHelper.Instance;

    /// <summary>
    /// 实体生成表
    /// </summary>
    /// <param name="stringDefaultLength"></param>
    /// <typeparam name="T"></typeparam>
    public static void CreateTable<T>(int stringDefaultLength = 255)
    {
        Db.CodeFirst.SetStringDefaultLength(stringDefaultLength).InitTables<T>();
    }

    /// <summary>
    /// 实体生成表
    /// </summary>
    /// <param name="stringDefaultLength"></param>
    /// <param name="types"></param>
    public static void CreateTable(int stringDefaultLength = 255, params Type[] types)
    {
        Db.CodeFirst.SetStringDefaultLength(stringDefaultLength).InitTables(types);
    }

    /// <summary>
    /// 表生成实体
    /// </summary>
    /// <param name="tableNames"></param>
    public static void CreateEntity(params string[] tableNames)
    {
        var projectName = Assembly.GetEntryAssembly()?.GetName().Name;
        if (!string.IsNullOrEmpty(projectName))
        {
            var path = Path.Combine(App.HostEnvironment.ContentRootPath, "Models");
            var space = projectName + ".Models";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            //默认方式
            // SqlDB.DbFirst.IsCreateAttribute().CreateClassFile(path, _namespace);
            Db.DbFirst
                //忽略
                .Where(tableNames)
                .IsCreateAttribute()
                //整个模版替换
                // .SettingClassTemplate(old => "xxx"+old+"xxx")
                //命名空间
                // .SettingNamespaceTemplate(s => s + "\r\nusing SqlSugar;\r\nusing ApiLib.Common.MyAttributes;")
                .SettingNamespaceTemplate(s => s + "using ApiLib.Common.MyAttributes;\r\n")
                //类名
                .FormatClassName(s => s.ToCamelCase(true))
                //文件名
                .FormatFileName(s => s.ToCamelCase(true))
                //高级自定义
                .SettingPropertyTemplate((column, temp, type) =>
                {
                    //temp中为模板，生成自定义内容后替换模板
                    //temp:{SugarColumn} public {PropertyType} {PropertyName} {get;set;}
                    //type:string
                    var columnAttribute = "\r\n        [SugarColumn({0})]";
                    var attributeContent = "ColumnName = \"" + column.DbColumnName + "\"";
                    if (column.IsPrimarykey)
                    {
                        attributeContent += ",IsPrimaryKey=true";
                        if (column.IsIdentity)
                        {
                            attributeContent += ",IsIdentity=true";
                        }
                    }

                    columnAttribute = string.Format(columnAttribute, attributeContent);
                    //NPOI特性
                    var desc = column.ColumnDescription;
                    if (string.IsNullOrEmpty(desc))
                    {
                        desc = column.DbColumnName;
                    }

                    columnAttribute += $"\r\n        [Excel(\"{desc}\")]";

                    return temp.Replace("{PropertyType}", type)
                        .Replace("{PropertyName}", column.DbColumnName.ToCamelCase(true))
                        .Replace("{SugarColumn}", columnAttribute);
                })
                .CreateClassFile(path, space);
        }
    }

    #region 配置

    
    /// <summary>
    /// 获取系统配置
    /// </summary>
    /// <returns></returns>
    public static List<SysConfig> GetAllSystemConfig()
    {
        return Db.Queryable<SysConfig>()
            .Where(config => config.Name == SystemModule)
            .ToList();
    }

    /// <summary>
    /// 获取系统配置
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public static SysConfig? GetSystemConfig(string key)
    {
        return GetConfig(SystemModule,key);
    }

    /// <summary>
    /// 保存系统配置
    /// </summary>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <returns></returns>
    public static void SetSystemConfig(string key, string value)
    {
        SetConfig(SystemModule, key, value);
    }

    /// <summary>
    /// 保存配置
    /// </summary>
    /// <param name="name">名称</param>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <returns></returns>
    public static void SetConfig(string name, string key, string value)
    {
        var first = Db.Queryable<SysConfig>()
            .First(config => config.Name == name && config.Key == key);
        first ??= new SysConfig
        {
            Name = name,
            Key = key
        };
        first.Value = value;
        first.InitSaveUser();
        Db.Storageable(first).ExecuteCommand();
    }

    /// <summary>
    /// 查询配置
    /// </summary>
    /// <param name="name">名称</param>
    /// <param name="key">键</param>
    /// <param name="value">值</param>
    /// <returns></returns>
    public static SysConfig? GetConfig(string name, string key)
    {
        var first = Db.Queryable<SysConfig>()
            .First(config => config.Name == name && config.Key == key);
        return first;
    }

    #endregion

    #region 缓存

    

    /// <summary>
    /// 获取缓存
    /// </summary>
    /// <param name="key"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T? CacheGet<T>(string key)
    {
        return RedisCache.UseRedis ? Redis.Get<T>(key) : Cache.Get<T>(key);
    }

    /// <summary>
    /// 设置缓存
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="expireSeconds">过去时间（秒）</param>
    /// <returns></returns>
    public static void CacheSet(string key, object value, int expireSeconds = -1)
    {
        if (RedisCache.UseRedis)
        {
            Redis.Set(key, value, expireSeconds);
        }
        else
        {
            if (expireSeconds > 0)
            {
                Cache.Set(key, value, TimeSpan.FromSeconds(expireSeconds));
            }
            else
            {
                Cache.Set(key, value);
            }
        }
    }

    /// <summary>
    /// 删除缓存
    /// </summary>
    /// <param name="key"></param>
    public static void CacheDel(string key)
    {
        if (RedisCache.UseRedis)
        {
            RedisCache.Del(key);
        }
        else
        {
            Cache.Remove(key);
        }
    }

    #endregion

    #region 用户缓存

    private static readonly Dictionary<string, string> LoginUserTokenCache = new();

    /// <summary>
    /// 获取缓存用户
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public static T? GetUserCache<T>(string key)
    {
        return CacheGet<T>(key);
        // return RedisCache.UseRedis ? RedisCache.Get<T>(key) : Cache.Get<T>(key);
    }

    /// <summary>
    /// 设置缓存用户
    /// </summary>
    /// <param name="key"></param>
    /// <param name="userinfo"></param>
    /// <returns></returns>
    public static void SetUserCache<T>(string key, T userinfo) where T : IBaseUser
    {
        var seconds = GlobalConfig.AppConfig?.UserLoginExpireSeconds ?? -1;
        FlushUser(userinfo.GetSid());
        CacheSet(key,userinfo,seconds);
        SetUserToken(userinfo.GetSid(), key);
    }

    /// <summary>
    /// 获取用户Token
    /// </summary>
    /// <param name="sid"></param>
    private static string? GetUserToken(string sid)
    {
        return RedisCache.UseRedis ? RedisCache.HGet(nameof(IBaseUser), sid) : LoginUserTokenCache.Get(sid);
    }
    
    /// <summary>
    /// 设置用户的token
    /// </summary>
    /// <param name="sid"></param>
    /// <param name="key"></param>
    private static void SetUserToken(string sid,string key)
    {
        if (RedisCache.UseRedis)
        {
            RedisCache.HSet(nameof(IBaseUser), sid, key);
        }
        else
        {
            LoginUserTokenCache[sid] = key;
        }
    }

    /// <summary>
    /// 刷新用户缓存
    /// </summary>
    /// <param name="sid"></param>
    public static void FlushUser(string sid)
    {
        var redisKey = GetUserToken(sid);
        if (!string.IsNullOrEmpty(redisKey))
        {
            CacheDel(redisKey);
        }
    }

    #endregion
}